/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = wtc_typed_fml.c                                    */
/*  NOTE      =                                                    */
/*  DATE      = 2015/08/26 by songbb                               */
/*******************************************************************/

#include "frreport_comm.h"
#include "frct_comm.h"

#include "../wtc_core.h"
#include "../wtc_comm.h"
#include "../wtc_mar.h"
#include "wtc_typed_fml.h"

FR_STATIC int __wtc_fldno(int i_fldid)
{
    return i_fldid & 0x1FFF;
}

FR_STATIC int __wtc_fldtype(int i_fldid)
{
    return i_fldid >> 13 & 0x7;
}

int wtc_typed_fml_tmpostrecv(Conntrack *p_st_conn
                            , L7session_wtc *p_st_sess
                            , L7_wtc_packet *p_st_wtc_packet
                            , int i_recv_size
                            , Frreport_body_data *p_st_body)
{
    WTC_PRINT_INFO("wtc_typed_fml_tmpostrecv...\n");
    return wtc_typed_fml_tmpostrecv65(p_st_conn, p_st_sess, p_st_wtc_packet, i_recv_size, p_st_body);
}

int wtc_typed_fml_tmpostrecv65(Conntrack *p_st_conn
                            , L7session_wtc *p_st_sess
                            , L7_wtc_packet *p_st_wtc_packet
                            , int i_recv_size
                            , Frreport_body_data *p_st_body)
{
    WTC_PRINT_INFO("wtc_typed_fml_tmpostrecv65...\n");
    L7_session *p_st_session = frct_get_session(p_st_conn);
    L7session_wtc_private *p_st_session_private = (L7session_wtc_private *) frct_get_session_private(p_st_session);
    L7_wtc_stmt *p_st_wtc_stmt = p_st_session_private->p_st_wtc_stmt;
    unsigned int ui_magic = 0;
    unsigned int ui_mynfields = 0;
    unsigned int ui_lcv;
    unsigned int ui_fldid = 0;
    int i_fldtype = 0;
    int i_pad = 0;
    int i_current_fldid = -1;
    unsigned int ui_tmp = 0;
    float f_tmp = 0;
    double d_tmp = 0;
    unsigned int ui_fldlen = 0;
    char *p_stringme = NULL;
    uint8_t byte;
    unsigned int ui_lcv2;
    char *p_value_carray = NULL;
    char *p_str = NULL;
    unsigned int ui_str_len = 0;
    char *p_field_name = NULL;
    int i_field_name_len = 0;

    if (bytebuff_get_int(p_st_wtc_packet->p_st_packet, 4, &ui_magic, BYTE_BIG_ENDIAN) != FR_SUCC)
        goto error;

    if (bytebuff_skip(p_st_wtc_packet->p_st_packet, 8) != FR_SUCC)
        goto error;

    if (bytebuff_get_int(p_st_wtc_packet->p_st_packet, 4, &ui_mynfields, BYTE_BIG_ENDIAN) != FR_SUCC)
        goto error;

    if (bytebuff_skip(p_st_wtc_packet->p_st_packet, 8) != FR_SUCC)
        goto error;

    for (ui_lcv = 0; ui_lcv < ui_mynfields; ui_lcv++)
    {
        if (bytebuff_get_int(p_st_wtc_packet->p_st_packet, 4, &ui_fldid, BYTE_BIG_ENDIAN) != FR_SUCC)
            goto error;
        if (__wtc_fldno(ui_fldid) == 0)
            goto error;
        i_fldtype = __wtc_fldtype((int) ui_fldid);

        WTC_PRINT_FATAL("ui_fldid:[%u] i_fldtype:[%d]\n", ui_fldid, i_fldtype);
        i_field_name_len = strlen(p_st_wtc_packet->i_is_req == FR_YES ? APM_DTS_REPORT_REQ_ARG_DATA : APM_DTS_REPORT_RESP_ARG_DATA) + 16;
        if ((p_field_name = (char *) frmalloc(i_field_name_len * sizeof(char))) == NULL)
        {
            WTC_MALLOCK_ERR;
            goto error;
        }
        snprintf(p_field_name, (size_t) i_field_name_len, "%s%d", p_st_wtc_packet->i_is_req == FR_YES ? APM_DTS_REPORT_REQ_ARG_DATA
                                                                                                      : APM_DTS_REPORT_RESP_ARG_DATA, __wtc_fldno(ui_fldid));

        switch (i_fldtype)
        {
            case APM_WTC_FLD_SHORT:
                if (i_current_fldid != (int) ui_fldid)
                {
                    i_current_fldid = ui_fldid;
                }
                if (bytebuff_get_int(p_st_wtc_packet->p_st_packet, 4, &ui_tmp, BYTE_BIG_ENDIAN) != FR_SUCC)
                    goto error;
                WTC_PRINT_ALERT("short:[%d]\n", ui_tmp);
                if (p_st_body != NULL)
                {
                    if (frreport_body_l7_add_uint(p_st_body, p_field_name, ui_tmp) != FR_SUCC)
                        goto error;
                    p_st_wtc_stmt->ui_arg_count++;
                }
                break;
            case APM_WTC_FLD_LONG:
                if (i_current_fldid != (int) ui_fldid)
                {
                    i_current_fldid = ui_fldid;
                }
                if (bytebuff_get_int(p_st_wtc_packet->p_st_packet, 4, &ui_tmp, BYTE_BIG_ENDIAN) != FR_SUCC)
                    goto error;
                WTC_PRINT_ALERT("int:[%d]\n", ui_tmp);
                if (p_st_body != NULL)
                {
                    if (frreport_body_l7_add_uint(p_st_body, p_field_name, ui_tmp) != FR_SUCC)
                        goto error;
                    p_st_wtc_stmt->ui_arg_count++;
                }
                break;
            case APM_WTC_FLD_CHAR:
                if (i_current_fldid != (int) ui_fldid)
                {
                    i_current_fldid = ui_fldid;
                }
                if (bytebuff_get_int(p_st_wtc_packet->p_st_packet, 4, &ui_tmp, BYTE_BIG_ENDIAN) != FR_SUCC)
                    goto error;
                WTC_PRINT_ALERT("char:[%d]\n", ui_tmp);
                if (p_st_body != NULL)
                {
                    if (frreport_body_l7_add_uint(p_st_body, p_field_name, ui_tmp) != FR_SUCC)
                        goto error;
                    p_st_wtc_stmt->ui_arg_count++;
                }
                break;
            case APM_WTC_FLD_FLOAT:
                if (i_current_fldid != (int) ui_fldid)
                {
                    i_current_fldid = ui_fldid;
                }
                if (wtc_mar_get_float(p_st_wtc_packet, &f_tmp) != FR_SUCC)
                    goto error;
                WTC_PRINT_ALERT("float:[%f]\n", f_tmp);
                if (p_st_body != NULL)
                {
                    if (frreport_body_l7_add_float(p_st_body, p_field_name, f_tmp) != FR_SUCC)
                        goto error;
                    p_st_wtc_stmt->ui_arg_count++;
                }
                break;
            case APM_WTC_FLD_DOUBLE:
                if (i_current_fldid != (int) ui_fldid)
                {
                    i_current_fldid = ui_fldid;
                }
                if (wtc_mar_get_double(p_st_wtc_packet, &d_tmp) != FR_SUCC)
                    goto error;
                WTC_PRINT_ALERT("double:[%f]\n", d_tmp);
                if (p_st_body != NULL)
                {
                    if (frreport_body_l7_add_double(p_st_body, p_field_name, d_tmp) != FR_SUCC)
                        goto error;
                    p_st_wtc_stmt->ui_arg_count++;
                }
                break;
            case APM_WTC_FLD_STRING:
                if (i_current_fldid != (int) ui_fldid)
                {
                    i_current_fldid = ui_fldid;
                }
                if (bytebuff_get_int(p_st_wtc_packet->p_st_packet, 4, &ui_fldlen, BYTE_BIG_ENDIAN) != FR_SUCC)
                    goto error;
                ui_fldlen = ui_fldlen - 2 - 2;
                i_pad = wtc_mar_roundup4(ui_fldlen) - ui_fldlen;
                WTC_PRINT_FATAL("i_pad:[%d]\n", i_pad);
                if (bytebuff_skip(p_st_wtc_packet->p_st_packet, 4) != FR_SUCC)
                    goto error;
                if (ui_fldlen <= 1)
                {
                    if (bytebuff_skip(p_st_wtc_packet->p_st_packet, (size_t) (i_pad + 1)) != FR_SUCC)
                        goto error;
                    WTC_PRINT_ALERT("string:[]\n");
                    if (p_st_body != NULL)
                    {
                        if (frreport_body_l7_add_str(p_st_body, p_field_name, "") != FR_SUCC)
                            goto error;
                        p_st_wtc_stmt->ui_arg_count++;
                    }
                }
                else
                {
                    if ((p_stringme = (char *) frmalloc((ui_fldlen - 1) * sizeof(char))) == NULL)
                    {
                        WTC_MALLOCK_ERR;
                        goto error;
                    }
                    for (ui_lcv2 = 0; ui_lcv2 < ui_fldlen - 1; ui_lcv2++)
                    {
                        if (bytebuff_get_char(p_st_wtc_packet->p_st_packet, &byte) != FR_SUCC)
                            goto error;
                        p_stringme[ui_lcv2] = byte;
                    }
                    if (bytebuff_skip(p_st_wtc_packet->p_st_packet, (size_t) (i_pad + 1)) != FR_SUCC)
                        goto error;
                    if (wtc_mar_get_mbstring(p_st_sess->p_default_encoding, p_stringme, ui_fldlen - 1, &p_str, &ui_str_len) != FR_SUCC)
                        goto error;
                    WTC_PRINT_ALERT("string:[%s]\n", p_str);
                    if (p_st_body != NULL)
                    {
                        if (frreport_body_l7_add_str(p_st_body, p_field_name, p_str) != FR_SUCC)
                            goto error;
                        p_st_wtc_stmt->ui_arg_count++;
                    }
                    wtc_free((void **) &p_stringme);
                    wtc_free((void **) &p_str);
                }
                break;
            case APM_WTC_FLD_CARRAY:
                if (i_current_fldid != (int) ui_fldid)
                {
                    i_current_fldid = ui_fldid;
                }
                if (bytebuff_get_int(p_st_wtc_packet->p_st_packet, 4, &ui_fldlen, BYTE_BIG_ENDIAN) != FR_SUCC)
                    goto error;
                ui_fldlen = ui_fldlen - 2 - 2;
                i_pad = wtc_mar_roundup4(ui_fldlen) - ui_fldlen;
                WTC_PRINT_FATAL("i_pad:[%d]\n", i_pad);
                if (bytebuff_skip(p_st_wtc_packet->p_st_packet, 4) != FR_SUCC)
                    goto error;
                if (ui_fldlen == 0)
                {
                    p_value_carray = NULL;
                    ui_fldlen = 0;
                }
                else
                {
                    if ((p_value_carray = (char *) frmalloc(ui_fldlen * sizeof(char))) == NULL)
                    {
                        WTC_MALLOCK_ERR;
                        goto error;
                    }
                    for (ui_lcv2 = 0; ui_lcv2 < ui_fldlen; ui_lcv2++)
                    {
                        if (bytebuff_get_char(p_st_wtc_packet->p_st_packet, &byte) != FR_SUCC)
                            goto error;
                        p_value_carray[ui_lcv2] = byte;
                    }
                    if (bytebuff_skip(p_st_wtc_packet->p_st_packet, (size_t) i_pad) != FR_SUCC)
                        goto error;
                }
                WTC_PRINT_ALERT("carray:[CARRAY]\n");
                if (p_st_body != NULL)
                {
                    if (frreport_body_l7_add_bin(p_st_body, p_field_name, p_value_carray, ui_fldlen) != FR_SUCC)
                        goto error;
                    p_st_wtc_stmt->ui_arg_count++;
                }
                wtc_free((void **) &p_value_carray);
                break;
            default:
                goto error;
        }

        wtc_free((void **) &p_field_name);
    }

    wtc_free((void **) &p_stringme);
    wtc_free((void **) &p_value_carray);
    return FR_SUCC;
error:
    wtc_free((void **) &p_field_name);
    wtc_free((void **) &p_stringme);
    wtc_free((void **) &p_str);
    wtc_free((void **) &p_value_carray);
    return FR_FAIL;
}

//////////////////////// for analyze direction
int wtc_typed_fml_tmpostrecv_fad(int i_recv_size
                            , char *p_payload
                            , unsigned int ui_payload_len
                            , unsigned int *p_ui_offset)
{
    return wtc_typed_fml_tmpostrecv65_fad(i_recv_size, p_payload, ui_payload_len, p_ui_offset);
}

int wtc_typed_fml_tmpostrecv65_fad(int i_recv_size
                                    , char *p_payload
                                    , unsigned int ui_payload_len
                                    , unsigned int *p_ui_offset)
{
    WTC_PRINT_INFO("wtc_typed_fml_tmpostrecv65_fad...\n");
    unsigned int ui_mynfields = 0;
    unsigned int ui_lcv;
    unsigned int ui_fldid = 0;
    int i_fldtype = 0;
    int i_pad = 0;
    unsigned int ui_fldlen = 0;

    if (wtc_skip_int(p_payload, ui_payload_len, p_ui_offset) != FR_SUCC) // ui_magic
        goto error;

    if (wtc_skip(p_payload, ui_payload_len, p_ui_offset, 8) != FR_SUCC)
        goto error;

    if (wtc_get_int(p_payload, ui_payload_len, p_ui_offset, &ui_mynfields) != FR_SUCC)
        goto error;

    if (wtc_skip(p_payload, ui_payload_len, p_ui_offset, 8) != FR_SUCC)
        goto error;

    for (ui_lcv = 0; ui_lcv < ui_mynfields; ui_lcv++)
    {
        if (wtc_get_int(p_payload, ui_payload_len, p_ui_offset, &ui_fldid) != FR_SUCC)
            goto error;
        if (__wtc_fldno(ui_fldid) == 0)
            goto error;
        i_fldtype = __wtc_fldtype((int) ui_fldid);

        WTC_PRINT_FATAL("ui_fldid:[%u] i_fldtype:[%d]\n", ui_fldid, i_fldtype);
        switch (i_fldtype)
        {
            case APM_WTC_FLD_SHORT:
            case APM_WTC_FLD_LONG:
            case APM_WTC_FLD_CHAR:
                if (wtc_skip_int(p_payload, ui_payload_len, p_ui_offset) != FR_SUCC)
                    goto error;
                break;
            case APM_WTC_FLD_FLOAT:
                if (wtc_skip_float(p_payload, ui_payload_len, p_ui_offset) != FR_SUCC)
                    goto error;
                break;
            case APM_WTC_FLD_DOUBLE:
                if (wtc_skip_double(p_payload, ui_payload_len, p_ui_offset) != FR_SUCC)
                    goto error;
                break;
            case APM_WTC_FLD_STRING:
                if (wtc_get_int(p_payload, ui_payload_len, p_ui_offset, &ui_fldlen) != FR_SUCC)
                    goto error;
                ui_fldlen = ui_fldlen - 2 - 2;
                i_pad = wtc_mar_roundup4(ui_fldlen) - ui_fldlen;
                WTC_PRINT_FATAL("i_pad:[%d]\n", i_pad);
                if (wtc_skip(p_payload, ui_payload_len, p_ui_offset, 4) != FR_SUCC)
                    goto error;
                if (ui_fldlen <= 1)
                {
                    if (wtc_skip(p_payload, ui_payload_len, p_ui_offset, i_pad + 1) != FR_SUCC)
                        goto error;
                }
                else
                {
                    if (wtc_skip(p_payload, ui_payload_len, p_ui_offset, ui_fldlen - 1) != FR_SUCC)
                        goto error;
                    if (wtc_skip(p_payload, ui_payload_len, p_ui_offset, i_pad + 1) != FR_SUCC)
                        goto error;
                }
                break;
            case APM_WTC_FLD_CARRAY:
                if (wtc_get_int(p_payload, ui_payload_len, p_ui_offset, &ui_fldlen) != FR_SUCC)
                    goto error;
                ui_fldlen = ui_fldlen - 2 - 2;
                i_pad = wtc_mar_roundup4(ui_fldlen) - ui_fldlen;
                WTC_PRINT_FATAL("i_pad:[%d]\n", i_pad);
                if (wtc_skip(p_payload, ui_payload_len, p_ui_offset, 4) != FR_SUCC)
                    goto error;
                if (ui_fldlen != 0)
                {
                    if (wtc_skip(p_payload, ui_payload_len, p_ui_offset, ui_fldlen) != FR_SUCC)
                        goto error;
                    if (wtc_skip(p_payload, ui_payload_len, p_ui_offset, i_pad) != FR_SUCC)
                        goto error;
                }
                break;
            default:
                goto error;
        }
    }

    return FR_SUCC;
error:
    return FR_FAIL;
}
